package SubjectTree.One;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

import Utility.TreeNode;

public class InorderTraversal {

/**
 * 难度：中等
 * 
 * 94. 二叉树的中序遍历
 * 	给定一个二叉树的根节点 root ，返回它的 中序 遍历。
 * 	
 * 示例 1：
 * 	输入：root = [1,null,2,3]
 * 	输出：[1,3,2]
 * 	
 * 示例 2：
 * 	输入：root = []
 * 	输出：[]
 * 	
 * 示例 3：
 * 	输入：root = [1]
 * 	输出：[1]
 * 	
 * 示例 4：
 * 	输入：root = [1,2]
 * 	输出：[2,1]
 * 	
 * 示例 5：
 * 	输入：root = [1,null,2]
 * 	输出：[1,2]
 * 	
 * 提示：
 * 	树中节点数目在范围 [0, 100] 内
 * 	-100 <= Node.val <= 100
 * 	
 * 进阶: 递归算法很简单，你可以通过迭代算法完成吗？
 * 
 * */
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		InorderTraversal it = new InorderTraversal();
		TreeNode root = new TreeNode(1);
		root.left = null;
		root.right = new TreeNode(2);
		root.right.left = new TreeNode(3);
//		TreeNode root = TreeNode.MkTree("[1,null,2,3]");
		System.out.println(it.inorderTraversal(root));
	}
	public List<Integer> inorderTraversal(TreeNode root) {
		List<Integer> list = new ArrayList<>();
		if(root==null)return list;
		Deque<TreeNode> deque = new LinkedList<>();
		TreeNode node = root;
		while(!deque.isEmpty()||node!=null) {
			while(node!=null) {
				deque.push(node);
				node = node.left;
			}
			node = deque.pop();
			list.add(node.val);
			node = node.right;
		}
		return list;
    }
	//方法一：递归
	public List<Integer> inorderTraversal1(TreeNode root) {
		List<Integer> list = new ArrayList<>();
		traversal(root,list);
		return list;
    }
	public void traversal(TreeNode root,List<Integer> list) {
		if(root == null) return;
		traversal(root.left,list);
		list.add(root.val);
		traversal(root.right,list);
	}
	//方法二：栈
	public List<Integer> inorderTraversal2(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        Deque<TreeNode> stk = new LinkedList<TreeNode>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {
                stk.push(root);
                root = root.left;
            }
            root = stk.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }
	//方法三：Morris 中序遍历
	public List<Integer> inorderTraversal3(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        TreeNode predecessor = null;

        while (root != null) {
            if (root.left != null) {
                // predecessor 节点就是当前 root 节点向左走一步，然后一直向右走至无法走为止
                predecessor = root.left;
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }
                
                // 让 predecessor 的右指针指向 root，继续遍历左子树
                if (predecessor.right == null) {
                    predecessor.right = root;
                    root = root.left;
                }
                // 说明左子树已经访问完了，我们需要断开链接
                else {
                    res.add(root.val);
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 如果没有左孩子，则直接访问右孩子
            else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}
